package day32.Optional;
import java.util.Optional;

/**
 * Optional类的功能测试
 * Optional是Java 8引入的一个容器类，代表一个值存在或不存在
 * 用于避免空指针异常(NullPointerException)
 * 
 * Optional类的主要作用：
 * 1. 提供了一种统一的、优雅的方式来处理可能为null的值
 * 2. 避免了直接使用null带来的空指针异常问题
 * 3. 强制开发者思考值不存在的情况，提高代码的健壮性
 * 4. 提供了丰富的API来处理可能存在或不存在的值
 * 
 * Optional类的设计理念：
 * - Optional对象本身永远不会为null，这是使用Optional的基本前提
 * - Optional对象要么包含一个值，要么为空(EMPTY)
 * - 通过提供丰富的API方法，让开发者能够以函数式编程的方式处理可能为空的值
 */
public class OptionalTest {
    public static void main(String[] args) {
        // 1. 创建Optional对象的不同方式
        // Optional提供了三种创建实例的方法，分别适用于不同的场景
        // 这些方法让我们能够根据不同的业务场景选择合适的创建方式
        System.out.println("=== 创建Optional对象 ===");
        
        // empty() - 创建一个空的Optional实例
        // 当我们确定要创建一个不包含任何值的Optional对象时使用
        // 这个方法返回一个空的Optional对象，其中不包含任何值
        Optional<String> emptyOptional = Optional.empty();
        System.out.println("emptyOptional: " + emptyOptional);
        
        // of() - 创建一个包含值的Optional实例，如果传入null会抛出NullPointerException
        // 当我们确定值不为null时使用此方法，如果传入null会立即抛出异常
        // 这个方法适用于我们明确知道值不为null的情况，如果传入null会抛出运行时异常
        Optional<String> nonNullOptional = Optional.of("Hello World");
        System.out.println("nonNullOptional: " + nonNullOptional);
        
        // ofNullable() - 创建一个允许null值的Optional实例
        // 当我们不确定值是否为null时使用此方法，它会自动处理null值情况
        // 这是最常用的方法，因为它能够安全地处理null和非null两种情况
        Optional<String> nullableOptional = Optional.ofNullable("May be null");
        System.out.println("nullableOptional: " + nullableOptional);
        Optional<String> nullOptional = Optional.ofNullable(null);
        System.out.println("nullOptional: " + nullOptional);
        
        // 2. 检查Optional对象的方法
        // 用于检查Optional对象中是否包含值
        // 这些方法帮助我们在不直接获取值的情况下判断Optional的状态
        System.out.println("\n=== 检查Optional对象 ===");
        // isPresent()方法用于检查Optional中是否有值，有值返回true，否则返回false
        // 这是Java 8中引入的方法，用于判断Optional对象是否包含值
        System.out.println("emptyOptional.isPresent(): " + emptyOptional.isPresent());
        // nonNullOptional中包含"Hello World"字符串，所以返回true
        // 当Optional包含值时，isPresent()方法返回true
        System.out.println("nonNullOptional.isPresent(): " + nonNullOptional.isPresent());
        // isEmpty()方法是Java 11新增的，与isPresent()相反，没有值时返回true
        // 这个方法是从Java 11开始提供的，提供了一种更直观的检查空值的方式
        /*System.out.println("nonNullOptional.isEmpty(): " + nonNullOptional.isEmpty()); // Java 11+*/
        
        // 3. 获取Optional中的值
        // 演示如何从Optional对象中获取值
        // 这些方法用于从Optional对象中提取包含的值，但需要注意处理空值情况
        System.out.println("\n=== 获取Optional中的值 ===");
        try {
            // get()方法用于获取Optional中的值，但如果Optional为空，则会抛出NoSuchElementException异常
            // 这是最直接但也是最危险的方法，因为如果Optional为空会抛出异常
            // 所以在使用get()方法之前，通常需要先使用isPresent()方法检查
            String value = nonNullOptional.get();
            System.out.println("通过get()获取值: " + value);
            
            // 对于空Optional调用get()会抛出NoSuchElementException
            // emptyOptional.get(); // 这行会抛异常，所以被注释掉了
            // 注意：直接使用get()方法是不推荐的，应该优先使用其他更安全的方法
        } catch (Exception e) {
            // 捕获可能的异常并打印错误信息
            // 实际开发中应该避免使用get()方法直接获取值，而应该使用更安全的方法
            System.out.println("获取空Optional的值时出错: " + e.getMessage());
        }
        
        // 4. 提供默认值的方法
        // 当Optional为空时，提供默认值的几种方式
        // 这些方法让我们能够优雅地处理空值情况，提供合理的默认行为
        System.out.println("\n=== 提供默认值 ===");
        // orElse()方法：如果Optional有值则返回该值，否则返回指定的默认值
        // 这是最常用的处理空值的方法之一，提供了简单的默认值机制
        String defaultValue = emptyOptional.orElse("默认值");
        System.out.println("emptyOptional.orElse(\"默认值\"): " + defaultValue);
        
        // orElseGet()方法：如果Optional有值则返回该值，否则调用Supplier接口提供的值
        // Supplier是一个函数式接口，通过lambda表达式提供默认值
        // 与orElse()不同的是，orElseGet()只有在需要时才会执行Supplier，性能更好
        String supplierValue = emptyOptional.orElseGet(() -> "通过Supplier提供的值");
        System.out.println("emptyOptional.orElseGet(...): " + supplierValue);
        
        // 5. 条件处理
        // 当Optional中有值时才执行特定操作
        // 这些方法让我们能够以函数式的方式处理值存在的情况
        System.out.println("\n=== 条件处理 ===");
        // ifPresent()方法：如果Optional中有值，则执行给定的Consumer操作（函数式接口）
        // 这里使用lambda表达式定义要执行的操作
        // Consumer是一个函数式接口，接受一个参数但不返回结果
        nonNullOptional.ifPresent(value -> System.out.println("值存在: " + value));
        // emptyOptional中没有值，所以不会执行lambda表达式中的打印操作
        // 这是一种非常优雅的处理方式，避免了显式的if判断
        emptyOptional.ifPresent(value -> System.out.println("这行不会执行"));
        
        // 6. 过滤值
        // 使用filter方法对Optional中的值进行条件过滤
        // 这个方法类似于Stream中的filter，用于根据条件筛选值
        System.out.println("\n=== 过滤值 ===");
        // 创建一个包含整数10的Optional对象
        // 我们将演示如何根据条件过滤Optional中的值
        Optional<Integer> number = Optional.of(10);
        // filter()方法：如果Optional中有值，且该值满足给定的断言条件(Predicate)，则返回包含该值的Optional
        // 否则返回一个空的Optional
        // Predicate是一个函数式接口，接受一个参数并返回boolean值
        Optional<Integer> filtered = number.filter(n -> n > 5);
        System.out.println("过滤大于5的数字10: " + filtered);
        
        // 由于10>15为false，所以filter返回空的Optional
        // 这展示了filter方法在条件不满足时的行为
        Optional<Integer> filteredOut = number.filter(n -> n > 15);
        System.out.println("过滤大于15的数字10: " + filteredOut);
        
        // 7. 转换值
        // 使用map方法对Optional中的值进行转换
        // 这个方法类似于Stream中的map，用于对值进行转换处理
        System.out.println("\n=== 转换值 ===");
        // 创建一个包含字符串"hello"的Optional对象
        // 我们将演示如何对Optional中的值进行转换操作
        Optional<String> text = Optional.of("hello");
        // map()方法：如果Optional中有值，则对该值应用给定的函数(Function)，并返回包含结果的Optional
        // 这里使用String::toUpperCase方法引用将字符串转换为大写
        // Function是一个函数式接口，接受一个参数并返回转换后的结果
        Optional<String> upperText = text.map(String::toUpperCase);
        System.out.println("转换为大写: " + upperText);
        
        // 对于空的Optional，map操作不会执行，直接返回空的Optional
        // 这体现了Optional的安全性，空值不会导致异常
        Optional<String> emptyText = Optional.empty();
        Optional<String> emptyUpperText = emptyText.map(String::toUpperCase);
        System.out.println("空Optional转换为大写: " + emptyUpperText);
        
        // 8. 扁平化转换
        // 使用flatMap处理嵌套的Optional对象
        // 这个方法用于处理Optional嵌套的情况，避免产生Optional<Optional<T>>这样的结构
        System.out.println("\n=== 扁平化转换 ===");
        // 创建一个嵌套的Optional对象，外层Optional包含一个内层Optional
        // 这种情况在实际开发中可能会遇到，比如方法返回Optional，而我们又对结果进行Optional包装
        Optional<Optional<String>> nestedOptional = Optional.of(Optional.of("nested"));
        // flatMap()方法：与map类似，但传入的函数返回的是Optional类型，不会产生嵌套的Optional
        // 这里直接返回内层的Optional对象，避免了Optional<Optional<String>>这种嵌套结构
        // flatMap常用于处理可能存在多层包装的情况
        Optional<String> flatOptional = nestedOptional.flatMap(opt -> opt);
        System.out.println("扁平化处理: " + flatOptional);
        
        /*
        9. or()方法 (Java 9+)
        // or()方法：如果Optional有值则返回自身，否则返回另一个Optional
        // 这个方法从Java 9开始提供，用于提供备选的Optional值
        System.out.println("\n=== or()方法 ===");
        Optional<String> first = Optional.empty();
        Optional<String> second = Optional.of("第二个值");
        Optional<String> result = first.of(() -> second);
        System.out.println("first.or(() -> second): " + result);
        
        System.out.println("\n=== 测试完成 ===");
        */
    }
}